package com.firefly.admin.monitor.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.firefly.admin.common.constant.Constants;
import com.firefly.admin.common.enums.ResultCodeEnum;
import com.firefly.admin.common.exception.BusinessException;
import com.firefly.admin.common.utils.DateUtil;
import com.firefly.admin.common.vo.Result;
import com.firefly.admin.monitor.entity.FyMonitorJob;
import com.firefly.admin.monitor.mapper.FyMonitorJobMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import com.firefly.admin.monitor.service.CommonJobService;
import com.firefly.admin.monitor.service.FyMonitorJobService;
import com.firefly.admin.monitor.vo.JobExecuteResult;
import com.firefly.admin.monitor.vo.MonitorJobQueryVo;
import com.firefly.admin.monitor.vo.MonitorJobStatusUpdateVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.util.List;

@Service
@Slf4j
public class FyMonitorJobServiceImpl implements FyMonitorJobService {

    @Autowired
    private FyMonitorJobMapper fyMonitorJobMapper;
    @Autowired
    private CommonJobService commonJobService;

    /**
     * 分页查询定时任务接口
     *
     * @param monitorJobQueryVo 定时任务查询条件
     * @return 定时任务信息列表
     */
    @Override
    public Result<Page<FyMonitorJob>> getJobPage(MonitorJobQueryVo monitorJobQueryVo) {
        LambdaQueryWrapper<FyMonitorJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(monitorJobQueryVo.getJobName()), FyMonitorJob::getJobName, monitorJobQueryVo.getJobName());
        queryWrapper.eq(StringUtils.isNotBlank(monitorJobQueryVo.getJobStatus()), FyMonitorJob::getJobStatus, monitorJobQueryVo.getJobStatus());
        queryWrapper.eq(FyMonitorJob::getDeleteFlag, Constants.DeleteFlag.NORMAL);
        queryWrapper.orderByDesc(FyMonitorJob::getJobId);
        queryWrapper.orderByAsc(FyMonitorJob::getJobStatus);
        Page<FyMonitorJob> page = new Page<>(monitorJobQueryVo.getPage(), monitorJobQueryVo.getLimit());
        Page<FyMonitorJob> monitorJobPage = fyMonitorJobMapper.selectPage(page, queryWrapper);
        return Result.success(monitorJobPage);
    }

    /**
     * 获取定时任务信息接口
     *
     * @param jobId 定时任务ID
     * @return 定时任务信息
     */
    @Override
    public Result<FyMonitorJob> getMonitorJob(Long jobId) {
        FyMonitorJob fyMonitorJob = fyMonitorJobMapper.selectById(jobId);
        if (fyMonitorJob == null) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_NOT_FOUND);
        }
        return Result.success(fyMonitorJob);
    }

    /**
     * 定时任务信息新增接口
     *
     * @param fyMonitorJob 定时任务信息
     * @return 新增结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<FyMonitorJob> add(FyMonitorJob fyMonitorJob) {
        if (fyMonitorJob == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        String jobName = fyMonitorJob.getJobName();
        if (StringUtils.isBlank(jobName)) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_NAME_NOT_NULL);
        }
        String jobClass = fyMonitorJob.getJobClass();
        if (StringUtils.isBlank(jobClass)) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_CLASS_NOT_NULL);
        }
        String jobMethodName = fyMonitorJob.getJobMethodName();
        if (StringUtils.isBlank(jobMethodName)) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_METHOD_NAME_NOT_NULL);
        }
        String jobCron = fyMonitorJob.getJobCron();
        if (StringUtils.isBlank(jobCron)) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_CRON_NOT_NULL);
        }
        fyMonitorJob.setLastExecuteResult(Constants.LastExecuteResult.NOT_EXECUTED);
        LambdaQueryWrapper<FyMonitorJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FyMonitorJob::getJobClass, jobClass);
        queryWrapper.eq(FyMonitorJob::getJobMethodName, jobMethodName);
        queryWrapper.eq(FyMonitorJob::getJobCron, jobCron);
        queryWrapper.eq(FyMonitorJob::getDeleteFlag, Constants.DeleteFlag.NORMAL);
        List<FyMonitorJob> monitorJobList = fyMonitorJobMapper.selectList(queryWrapper);
        if (!CollectionUtils.isEmpty(monitorJobList)) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_EXIST);
        }
        String jobStatus = fyMonitorJob.getJobStatus();
        if (StringUtils.isBlank(jobStatus)) {
            fyMonitorJob.setJobStatus(Constants.JobStatus.STOP);
        }
        fyMonitorJob.setCreateTime(DateUtil.getNowDate());
        int rows = fyMonitorJobMapper.insert(fyMonitorJob);
        if (rows <= 0) {
            return Result.getResult(ResultCodeEnum.ADD_EXCEPTION);
        }
        if (Constants.JobStatus.START.equals(jobStatus)) {
            Boolean executeResult = executeJob(fyMonitorJob);
            if (!executeResult) {
                throw new BusinessException(ResultCodeEnum.MONITOR_JOB_START_EXECUTE_EXCEPTION.getMsg());
            }
        }
        return Result.success(fyMonitorJob);
    }

    /**
     * 定时任务信息编辑接口
     *
     * @param fyMonitorJob 定时任务信息
     * @return 编辑结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<FyMonitorJob> update(FyMonitorJob fyMonitorJob) {
        if (fyMonitorJob == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        Long jobId = fyMonitorJob.getJobId();
        if (jobId == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        FyMonitorJob monitorJob = fyMonitorJobMapper.selectById(jobId);
        if (monitorJob == null) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_NOT_FOUND);
        }
        String jobStatus = monitorJob.getJobStatus();
        if (Constants.JobStatus.START.equals(jobStatus)) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_RUNNING_NOT_ALLOW_UPDATE);
        }
        String jobName = fyMonitorJob.getJobName();
        if (StringUtils.isBlank(jobName)) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_NAME_NOT_NULL);
        }
        String jobClass = fyMonitorJob.getJobClass();
        if (StringUtils.isBlank(jobClass)) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_CLASS_NOT_NULL);
        }
        if (!jobClass.equals(monitorJob.getJobClass())) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_CLASS_NOT_ALLOW_UPDATE);
        }
        String jobMethodName = fyMonitorJob.getJobMethodName();
        if (StringUtils.isBlank(jobMethodName)) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_METHOD_NAME_NOT_NULL);
        }
        if (!jobMethodName.equals(monitorJob.getJobMethodName())) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_METHOD_NAME_NOT_ALLOW_UPDATE);
        }
        String jobCron = fyMonitorJob.getJobCron();
        if (StringUtils.isBlank(jobCron)) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_CRON_NOT_NULL);
        }
        LambdaQueryWrapper<FyMonitorJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FyMonitorJob::getJobClass, jobClass);
        queryWrapper.eq(FyMonitorJob::getJobMethodName, jobMethodName);
        queryWrapper.eq(FyMonitorJob::getJobCron, jobCron);
        queryWrapper.eq(FyMonitorJob::getDeleteFlag, Constants.DeleteFlag.NORMAL);
        List<FyMonitorJob> monitorJobList = fyMonitorJobMapper.selectList(queryWrapper);
        if (!CollectionUtils.isEmpty(monitorJobList)) {
            for (FyMonitorJob job : monitorJobList) {
                if (jobId.longValue() != job.getJobId().longValue()) {
                    return Result.getResult(ResultCodeEnum.MONITOR_JOB_EXIST);
                }
            }
        }
        if (Constants.JobStatus.START.equals(fyMonitorJob.getJobStatus())) {
            Boolean executeResult = executeJob(fyMonitorJob);
            if (!executeResult) {
                throw new BusinessException(ResultCodeEnum.MONITOR_JOB_START_EXECUTE_EXCEPTION.getMsg());
            }
        }
        int rows = fyMonitorJobMapper.updateById(fyMonitorJob);
        if (rows <= 0) {
            return Result.getResult(ResultCodeEnum.UPDATE_EXCEPTION);
        }
        return Result.success(fyMonitorJob);
    }

    private Boolean executeJob(FyMonitorJob fyMonitorJob) {
        boolean executeResult = true;
        if (Constants.ExecutionPolicy.EXECUTE_IMMEDIATELY.equals(fyMonitorJob.getExecutionPolicy())) {
            //启动定时任务
            Result<FyMonitorJob> gcCronJobResult = commonJobService.startJob(fyMonitorJob);
            if (gcCronJobResult.getCode().intValue() != ResultCodeEnum.SUCCESS.getCode()) {
                executeResult = false;
            }
        }
        if (Constants.ExecutionPolicy.EXECUTE_ONCE.equals(fyMonitorJob.getExecutionPolicy())) {
            //执行一次定时任务
            Result<JobExecuteResult> jobExecuteResult = commonJobService.executeOnceJob(fyMonitorJob);
            if (jobExecuteResult.getCode().intValue() != ResultCodeEnum.SUCCESS.getCode()) {
                executeResult = false;
            }
            fyMonitorJob.setJobStatus(Constants.JobStatus.STOP);
        }
        if (Constants.ExecutionPolicy.ABANDON_EXECUTION.equals(fyMonitorJob.getExecutionPolicy())) {
            //放弃执行定时任务
            throw new BusinessException(ResultCodeEnum.MONITOR_JOB_ABANDON_EXECUTION.getMsg());
        }
        return executeResult;
    }

    /**
     * 定时任务状态修改接口
     *
     * @param monitorJobStatusUpdateVo 定时任务状态编辑参数
     * @return 操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<FyMonitorJob> updateStatus(MonitorJobStatusUpdateVo monitorJobStatusUpdateVo) {
        if (monitorJobStatusUpdateVo == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        Long jobId = monitorJobStatusUpdateVo.getJobId();
        if (jobId == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        FyMonitorJob monitorJob = fyMonitorJobMapper.selectById(jobId);
        if (monitorJob == null) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_NOT_FOUND);
        }
        String jobStatus = monitorJobStatusUpdateVo.getJobStatus();
        monitorJob.setJobStatus(jobStatus);
        if (Constants.JobStatus.START.equals(jobStatus)) {
            String executionPolicy = monitorJobStatusUpdateVo.getExecutionPolicy();
            monitorJob.setExecutionPolicy(executionPolicy);
            Boolean executeResult = executeJob(monitorJob);
            if (!executeResult) {
                throw new BusinessException(ResultCodeEnum.MONITOR_JOB_START_EXECUTE_EXCEPTION.getMsg());
            }
        } else {
            if (Constants.ExecutionPolicy.EXECUTE_IMMEDIATELY.equals(monitorJob.getExecutionPolicy())) {
                //关闭定时任务
                commonJobService.stopJob(monitorJob);
            }
        }
        int rows = fyMonitorJobMapper.updateById(monitorJob);
        if (rows <= 0) {
            return Result.getResult(ResultCodeEnum.UPDATE_EXCEPTION);
        }
        return Result.success();
    }


    /**
     * 定时任务信息删除接口
     *
     * @param jobId 定时任务ID
     * @return 删除结果
     */
    @Override
    public Result<String> delete(Long jobId) {
        if (jobId == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        FyMonitorJob monitorJob = fyMonitorJobMapper.selectById(jobId);
        if (monitorJob == null) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_NOT_FOUND);
        }
        String jobStatus = monitorJob.getJobStatus();
        if (Constants.JobStatus.START.equals(jobStatus)) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_RUNNING_NOT_ALLOW_DELETE);
        }
        monitorJob.setDeleteFlag(Constants.DeleteFlag.DELETE);
        int rows = fyMonitorJobMapper.updateById(monitorJob);
        if (rows <= 0) {
            return Result.getResult(ResultCodeEnum.DELETE_EXCEPTION);
        }
        return Result.success();
    }

    /**
     * 手动执行任务接口
     *
     * @param jobId 定时任务ID
     * @return 执行结果
     */
    @Override
    public Result<JobExecuteResult> handExecute(Long jobId) {
        if (jobId == null) {
            return Result.getResult(ResultCodeEnum.REQUEST_PARAM_EXCEPTION);
        }
        FyMonitorJob monitorJob = fyMonitorJobMapper.selectById(jobId);
        if (monitorJob == null) {
            return Result.getResult(ResultCodeEnum.MONITOR_JOB_NOT_FOUND);
        }
        return commonJobService.executeOnceJob(monitorJob);
    }

    /**
     * 记录定时任务最后一次执行结果
     *
     * @param jobId             定时任务信息
     * @param lastExecuteResult 最后一次执行结果
     */
    @Override
    public void updateLastExecuteResult(Long jobId, String lastExecuteResult) {
        fyMonitorJobMapper.updateLastExecuteResult(jobId, lastExecuteResult);
    }

    @PostConstruct
    private void initJob() {
        LambdaQueryWrapper<FyMonitorJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FyMonitorJob::getJobStatus, Constants.JobStatus.START);
        queryWrapper.eq(FyMonitorJob::getExecutionPolicy, Constants.ExecutionPolicy.EXECUTE_IMMEDIATELY);
        List<FyMonitorJob> gcCronJobList = fyMonitorJobMapper.selectList(queryWrapper);
        if (!CollectionUtils.isEmpty(gcCronJobList)) {
            gcCronJobList.forEach(gcCronJob -> {
                try {
                    Boolean executeResult = executeJob(gcCronJob);
                    if (!executeResult) {
                        throw new BusinessException("定时任务执行异常，请联系管理员！");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    }
}
